// 元のページへの影響を最小限にするため、
// グローバルに定義された $関数を元に戻す
jQuery.noConflict();

// クロージャの中のみ$関数の定義はjQueryの定義が有効
(function($) {

  // 与えられたスクレープ定義情報をもとに
  // DOMツリーを検索しデータをオブジェクトとして返す
  jQuery.fn.scrape = function(def) {

    // DOMノードからテキスト値を取得
    function getText(n) { return n && $(n).text() }

    // DOMノードから属性値を取得する関数を作成
    function getAttr(a) {
      return function(n) { return n && $(n).attr(a) }
    }

    // DOMノードを定義情報に従ってJavaScriptオブジェクトに変換する関数を作成
    function getRecord(o) {
      return function(n) {
        if (!n) return null;
        var rec = {}
        for (var k in o) {
          if (o.hasOwnProperty(k)) rec[k] = $(n).scrape(o[k]);
        }
        return rec; 
      }
    }
    
    if (typeof def == 'string') def = { selector : def };

    var value = def.value;
    var type = typeof value;
    var toValue = 
      type=='function'      ? value : // カスタムの変換関数を適用
      type=='object'        ? getRecord(value) : // JavaScriptオブジェクトとして取得
      type=='string' && 
      value.indexOf('@')==0 ? getAttr(value.substring(1)) : // 属性値を取得
                              getText; // テキスト値を取得

    return def.array ? 
           this.find(def.selector).map(function() { return toValue(this) }) :
           toValue(this.find(def.selector).get(0));
  }

  //
  // 定義情報に従ってスクレープを実行
  var records = $(document).scrape({
    selector : '#FrmPrdCompare > div.elementBox',
    array : true,
    value : {
      title : 'div:first > div.rightBox a',
      link : {
        selector : 'div:first > div.rightBox a',
        value : '@href'
      },
      price : {
        selector : 'span.price',
        value : function(n) {
          return parseInt(n.firstChild.data.replace(/[^\d]/g,''));
        }
      }
    }
  });

  // Flotの受け取る描画形式に変更
  var prices = $.map(records, function(record, i) { return [ [ i+.6, record.price ] ] });

  // グラフ描画を行うコンテナ要素をドキュメントに追加
  var container = $('<div />')
    .css({
      position : 'absolute', top : '50px', left : '50px', 
      border : '1px solid #aaa',
      textAlign : 'right',
      backgroundColor : '#fff'
    })
    .appendTo(document.body)
    .append($('<a />').text('Close').click(function() { $(this).parent().remove() }))
    .append($('<div />').width(800).height(300))
    .find('div:last');

  // Flot によるグラフ描画
  // パラメータの詳細はFlot APIドキュメントを参照
  // http://flot.googlecode.com/svn/trunk/API.txt
  var plot = $.plot(container, [
    { data : prices, label : '価格' }
  ], {
    bars : { show : true, barWidth : .8 },
    xaxis : { ticks : [ [1, '1位'], [5,'5位'], [10,'10位'], [15,'15位'], [20, '20位'] ] },
    legend : { position : 'nw' },
    grid: { hoverable: true, clickable: true }
  });

  // マウスオーバー時に表示するツールチップ
  var tooltip = $('<div />')
    .css({
      position : 'absolute',
      top : 0, left : 0,
      border : '1px solid #aaa',
      padding : '5px',
      fontSize : '10px',
      backgroundColor : '#eef'
    })
    .hide()
    .appendTo(document.body);

  // マウスオーバー時の動作設定
  container.bind('plothover', function(e, pos, item) {
    if (item) {
      var record = records[item.dataIndex];
      tooltip.text(record.title + ' : ' + record.price + '円')
             .css('top', pos.pageY)
             .css('left', pos.pageX + 20)
             .show();
    } else {
      tooltip.hide();
    }
  });

  // クリック時の動作設定
  container.bind('plotclick', function(e, pos, item) {
    if (item) location.href = records[item.dataIndex].link;
  });


  //
  // Gears APIを利用してローカルDBにデータを永続的に保存
  //
  var db = google.gears.factory.create('beta.database');
  db.open('scraper-product-ranking');
  db.execute('create table if not exists ProductRanking' +
             ' (Title text, Link text, Price int, Rank int, Timestamp int)');
  var now = new Date().getTime();
  $.each(records, function(i, record) {
    db.execute('insert into ProductRanking values (?, ?, ?, ?, ?)', 
               [ record.title, record.link, record.price, i+1, now ]);
  });

  alert('ローカルデータベースへの保存が完了しました');


})(jQuery);
